﻿using System;
using UnityEngine;

namespace RootMotion.FinalIK
{
	// Token: 0x0200002E RID: 46
	public class FBBIKHeadEffector : MonoBehaviour
	{
		// Token: 0x06000234 RID: 564 RVA: 0x000225A8 File Offset: 0x000207A8
		public void Start()
		{
			IKSolverFullBodyBiped solver = this.ik.solver;
			solver.OnPreRead = (IKSolver.UpdateDelegate)Delegate.Combine(solver.OnPreRead, new IKSolver.UpdateDelegate(this.OnPreRead));
			IKSolverFullBodyBiped solver2 = this.ik.solver;
			solver2.OnPreIteration = (IKSolver.IterationDelegate)Delegate.Combine(solver2.OnPreIteration, new IKSolver.IterationDelegate(this.Iterate));
			IKSolverFullBodyBiped solver3 = this.ik.solver;
			solver3.OnPostUpdate = (IKSolver.UpdateDelegate)Delegate.Combine(solver3.OnPostUpdate, new IKSolver.UpdateDelegate(this.OnPostUpdate));
			this.headRotationRelativeToRoot = Quaternion.Inverse(this.ik.references.root.rotation) * this.ik.references.head.rotation;
		}

		// Token: 0x06000235 RID: 565 RVA: 0x00022674 File Offset: 0x00020874
		public void OnPreRead()
		{
			if (!base.enabled)
			{
				return;
			}
			if (!base.gameObject.activeInHierarchy)
			{
				return;
			}
			if (this.ik.solver.iterations == 0)
			{
				return;
			}
			this.SpineBend();
			this.CCDPass();
			this.offset = base.transform.position - this.ik.references.head.position;
			this.shoulderDist = Vector3.Distance(this.ik.references.leftUpperArm.position, this.ik.references.rightUpperArm.position);
			this.leftShoulderDist = Vector3.Distance(this.ik.references.head.position, this.ik.references.leftUpperArm.position);
			this.rightShoulderDist = Vector3.Distance(this.ik.references.head.position, this.ik.references.rightUpperArm.position);
			this.headToBody = this.ik.solver.rootNode.position - this.ik.references.head.position;
			this.headToLeftThigh = this.ik.references.leftThigh.position - this.ik.references.head.position;
			this.headToRightThigh = this.ik.references.rightThigh.position - this.ik.references.head.position;
			this.leftShoulderPos = this.ik.references.leftUpperArm.position + this.offset * this.bodyWeight;
			this.rightShoulderPos = this.ik.references.rightUpperArm.position + this.offset * this.bodyWeight;
			this.chestRotation = Quaternion.LookRotation(this.ik.references.head.position - this.ik.references.leftUpperArm.position, this.ik.references.rightUpperArm.position - this.ik.references.leftUpperArm.position);
		}

		// Token: 0x06000236 RID: 566 RVA: 0x000228F4 File Offset: 0x00020AF4
		public void SpineBend()
		{
			if (this.bendWeight <= 0f)
			{
				return;
			}
			if (this.bendBones.Length == 0)
			{
				return;
			}
			Quaternion b = base.transform.rotation * Quaternion.Inverse(this.ik.references.root.rotation * this.headRotationRelativeToRoot);
			float num = 1f / (float)this.bendBones.Length;
			for (int i = 0; i < this.bendBones.Length; i++)
			{
				if (this.bendBones[i].transform != null)
				{
					this.bendBones[i].transform.rotation = Quaternion.Lerp(Quaternion.identity, b, num * this.bendBones[i].weight * this.bendWeight) * this.bendBones[i].transform.rotation;
				}
			}
		}

		// Token: 0x06000237 RID: 567 RVA: 0x000229E4 File Offset: 0x00020BE4
		public void CCDPass()
		{
			if (this.CCDWeight <= 0f)
			{
				return;
			}
			for (int i = this.CCDBones.Length - 1; i > -1; i--)
			{
				Quaternion quaternion = Quaternion.FromToRotation(this.ik.references.head.position - this.CCDBones[i].position, base.transform.position - this.CCDBones[i].position) * this.CCDBones[i].rotation;
				float num = Mathf.Lerp((float)((this.CCDBones.Length - i) / this.CCDBones.Length), 1f, this.roll);
				float num2 = Quaternion.Angle(Quaternion.identity, quaternion);
				num2 = Mathf.Lerp(0f, num2, (this.damper - num2) / this.damper);
				this.CCDBones[i].rotation = Quaternion.RotateTowards(this.CCDBones[i].rotation, quaternion, num2 * this.CCDWeight * num);
			}
		}

		// Token: 0x06000238 RID: 568 RVA: 0x00022AF0 File Offset: 0x00020CF0
		public void Iterate(int iteration)
		{
			if (!base.enabled)
			{
				return;
			}
			if (!base.gameObject.activeInHierarchy)
			{
				return;
			}
			if (this.ik.solver.iterations == 0)
			{
				return;
			}
			this.leftShoulderPos = base.transform.position + (this.leftShoulderPos - base.transform.position).normalized * this.leftShoulderDist;
			this.rightShoulderPos = base.transform.position + (this.rightShoulderPos - base.transform.position).normalized * this.rightShoulderDist;
			this.Solve(ref this.leftShoulderPos, ref this.rightShoulderPos, this.shoulderDist);
			this.LerpSolverPosition(this.ik.solver.leftShoulderEffector, this.leftShoulderPos, this.positionWeight);
			this.LerpSolverPosition(this.ik.solver.rightShoulderEffector, this.rightShoulderPos, this.positionWeight);
			Quaternion to = Quaternion.LookRotation(base.transform.position - this.leftShoulderPos, this.rightShoulderPos - this.leftShoulderPos);
			Quaternion quaternion = QuaTools.FromToRotation(this.chestRotation, to);
			Vector3 b = quaternion * this.headToBody;
			this.LerpSolverPosition(this.ik.solver.bodyEffector, base.transform.position + b, this.positionWeight);
			Quaternion rotation = Quaternion.Lerp(Quaternion.identity, quaternion, this.thighWeight);
			Vector3 b2 = rotation * this.headToLeftThigh;
			Vector3 b3 = rotation * this.headToRightThigh;
			this.LerpSolverPosition(this.ik.solver.leftThighEffector, base.transform.position + b2, this.positionWeight);
			this.LerpSolverPosition(this.ik.solver.rightThighEffector, base.transform.position + b3, this.positionWeight);
		}

		// Token: 0x06000239 RID: 569 RVA: 0x00022D0C File Offset: 0x00020F0C
		public void OnPostUpdate()
		{
			if (!base.enabled)
			{
				return;
			}
			if (!base.gameObject.activeInHierarchy)
			{
				return;
			}
			this.Stretching();
			this.ik.references.head.rotation = Quaternion.Lerp(this.ik.references.head.rotation, base.transform.rotation, this.rotationWeight);
		}

		// Token: 0x0600023A RID: 570 RVA: 0x00022D7C File Offset: 0x00020F7C
		public void Stretching()
		{
			if (this.stretchWeight <= 0f)
			{
				return;
			}
			Vector3 a = Vector3.ClampMagnitude(base.transform.position - this.ik.references.head.position, this.maxStretch);
			a *= this.stretchWeight;
			this.stretchDamper = Mathf.Max(this.stretchDamper, 0f);
			if (this.stretchDamper > 0f)
			{
				a /= (1f + a.magnitude) * (1f + this.stretchDamper);
			}
			for (int i = 0; i < this.stretchBones.Length; i++)
			{
				if (this.stretchBones[i] != null)
				{
					this.stretchBones[i].position += a / (float)this.stretchBones.Length;
				}
			}
			if (this.fixHead)
			{
				this.ik.references.head.position = base.transform.position;
			}
		}

		// Token: 0x0600023B RID: 571 RVA: 0x00003884 File Offset: 0x00001A84
		public void LerpSolverPosition(IKEffector effector, Vector3 position, float weight)
		{
			effector.GetNode(this.ik.solver).solverPosition = Vector3.Lerp(effector.GetNode(this.ik.solver).solverPosition, position, weight);
		}

		// Token: 0x0600023C RID: 572 RVA: 0x00022EA0 File Offset: 0x000210A0
		public void Solve(ref Vector3 pos1, ref Vector3 pos2, float nominalDistance)
		{
			Vector3 a = pos2 - pos1;
			float magnitude = a.magnitude;
			if (magnitude == nominalDistance)
			{
				return;
			}
			if (magnitude == 0f)
			{
				return;
			}
			float num = 1f;
			num *= 1f - nominalDistance / magnitude;
			Vector3 b = a * num * 0.5f;
			pos1 += b;
			pos2 -= b;
		}

		// Token: 0x0600023D RID: 573 RVA: 0x00022F24 File Offset: 0x00021124
		public void OnDestroy()
		{
			if (this.ik != null)
			{
				IKSolverFullBodyBiped solver = this.ik.solver;
				solver.OnPreRead = (IKSolver.UpdateDelegate)Delegate.Remove(solver.OnPreRead, new IKSolver.UpdateDelegate(this.OnPreRead));
				IKSolverFullBodyBiped solver2 = this.ik.solver;
				solver2.OnPreIteration = (IKSolver.IterationDelegate)Delegate.Remove(solver2.OnPreIteration, new IKSolver.IterationDelegate(this.Iterate));
				IKSolverFullBodyBiped solver3 = this.ik.solver;
				solver3.OnPostUpdate = (IKSolver.UpdateDelegate)Delegate.Remove(solver3.OnPostUpdate, new IKSolver.UpdateDelegate(this.OnPostUpdate));
			}
		}

		// Token: 0x0400012B RID: 299
		[Tooltip("Reference to the FBBIK component.")]
		public FullBodyBipedIK ik;

		// Token: 0x0400012C RID: 300
		[Header("Position")]
		[Tooltip("Master weight for positioning the head.")]
		[Range(0f, 1f)]
		public float positionWeight = 1f;

		// Token: 0x0400012D RID: 301
		[Tooltip("The weight of moving the body along with the head")]
		[Range(0f, 1f)]
		public float bodyWeight = 0.8f;

		// Token: 0x0400012E RID: 302
		[Range(0f, 1f)]
		[Tooltip("The weight of moving the thighs along with the head")]
		public float thighWeight = 0.8f;

		// Token: 0x0400012F RID: 303
		[Header("Rotation")]
		[Range(0f, 1f)]
		[Tooltip("The weight of rotating the head bone after solving")]
		public float rotationWeight;

		// Token: 0x04000130 RID: 304
		[Tooltip("The master weight of bending/twisting the spine to the rotation of the head effector. This is similar to CCD, but uses the rotation of the head effector not the position.")]
		[Range(0f, 1f)]
		public float bendWeight = 1f;

		// Token: 0x04000131 RID: 305
		[Tooltip("The bones to use for bending.")]
		public FBBIKHeadEffector.BendBone[] bendBones = new FBBIKHeadEffector.BendBone[0];

		// Token: 0x04000132 RID: 306
		[Header("CCD")]
		[Tooltip("Optional. The master weight of the CCD (Cyclic Coordinate Descent) IK effect that bends the spine towards the head effector before FBBIK solves.")]
		[Range(0f, 1f)]
		public float CCDWeight = 1f;

		// Token: 0x04000133 RID: 307
		[Tooltip("The weight of rolling the bones in towards the target")]
		[Range(0f, 1f)]
		public float roll;

		// Token: 0x04000134 RID: 308
		[Range(0f, 1000f)]
		[Tooltip("Smoothing the CCD effect.")]
		public float damper = 500f;

		// Token: 0x04000135 RID: 309
		[Tooltip("Bones to use for the CCD pass. Assign spine and/or neck bones.")]
		public Transform[] CCDBones = new Transform[0];

		// Token: 0x04000136 RID: 310
		[Tooltip("Stretching the spine/neck to help reach the target. This is useful for making sure the head stays locked relative to the VR headset. NB! Stretching is done after FBBIK has solved so if you have the hand effectors pinned and spine bones included in the 'Stretch Bones', the hands might become offset from their target positions.")]
		[Header("Stretching")]
		[Range(0f, 1f)]
		public float stretchWeight = 1f;

		// Token: 0x04000137 RID: 311
		[Tooltip("Stretch magnitude limit.")]
		public float maxStretch = 0.1f;

		// Token: 0x04000138 RID: 312
		[Tooltip("If > 0, dampers the stretching effect.")]
		public float stretchDamper;

		// Token: 0x04000139 RID: 313
		[Tooltip("If true, will fix head position to this Transform no matter what. Good for making sure the head will not budge away from the VR headset")]
		public bool fixHead;

		// Token: 0x0400013A RID: 314
		[Tooltip("Bones to use for stretching. The more bones you add, the less noticable the effect.")]
		public Transform[] stretchBones = new Transform[0];

		// Token: 0x0400013B RID: 315
		public Vector3 offset;

		// Token: 0x0400013C RID: 316
		public Vector3 headToBody;

		// Token: 0x0400013D RID: 317
		public Vector3 shoulderCenterToHead;

		// Token: 0x0400013E RID: 318
		public Vector3 headToLeftThigh;

		// Token: 0x0400013F RID: 319
		public Vector3 headToRightThigh;

		// Token: 0x04000140 RID: 320
		public Vector3 leftShoulderPos;

		// Token: 0x04000141 RID: 321
		public Vector3 rightShoulderPos;

		// Token: 0x04000142 RID: 322
		public float shoulderDist;

		// Token: 0x04000143 RID: 323
		public float leftShoulderDist;

		// Token: 0x04000144 RID: 324
		public float rightShoulderDist;

		// Token: 0x04000145 RID: 325
		public Quaternion chestRotation;

		// Token: 0x04000146 RID: 326
		public Quaternion headRotationRelativeToRoot;

		// Token: 0x0200002F RID: 47
		[Serializable]
		public class BendBone
		{
			// Token: 0x0600023E RID: 574 RVA: 0x000038B9 File Offset: 0x00001AB9
			public BendBone()
			{
			}

			// Token: 0x0600023F RID: 575 RVA: 0x000038CC File Offset: 0x00001ACC
			public BendBone(Transform transform, float weight)
			{
				this.transform = transform;
				this.weight = weight;
			}

			// Token: 0x04000147 RID: 327
			[Tooltip("Assign spine and/or neck bones.")]
			public Transform transform;

			// Token: 0x04000148 RID: 328
			[Range(0f, 1f)]
			[Tooltip("The weight of rotating this bone.")]
			public float weight = 0.5f;
		}
	}
}
